from rest_framework.decorators import action
from rest_framework.generics import GenericAPIView
from rest_framework.viewsets import GenericViewSet

from threedGestureProject.common.filter import SearchField
from threedGestureProject.common.mixins import MCreateModelMixin, MUpdateModelMixin
from threedGestureProject.common.result import BaseResponse, ResultCode
from threedGestureProject.common.viewset import BaseViewSet, TokenViewSet
from .models import DbCourse, User, DbCourseVideo, UserToken, DbCourseType, DbStudyRecord
from .serializers import UserSerializer, CourseSerializer, CourseVideoSerializer, UserTokenSerializer, \
    CourseTypeSerializer, StudyRecordSerializer
import threedGestureProject.common.tools as tools


# noinspection PyShadowingNames
class UserApi(GenericViewSet):
    """ 用户相关接口 """
    LOGIN_ACTION = 'login'

    REGISTER_ACTION = 'register'

    queryset = User.objects.all()
    serializer_class = UserSerializer

    def get_user(self, user_id):
        user = None
        try:
            user = self.queryset.get(id=user_id)
        except User.DoesNotExist:
            pass
        return user

    def user_checking(self, request, username):
        """
        用户名检测 检测一个用户名是否已经存在
        :param request: 请求
        :param username: 用户名
        :return: 检测结果
        """
        user_count = self.queryset.filter(username=username).count()
        if user_count and user_count > 0:
            return BaseResponse(message='用户已存在', data=False)
        return BaseResponse(message='用户名可使用', data=True)

    def post(self, request, action=None):
        if action == ('%s' % self.REGISTER_ACTION):
            return self.do_register(request)
        elif action == ('%s' % self.LOGIN_ACTION):
            return self.do_login(request)
        else:
            return BaseResponse(message='error')

    def do_register(self, request):
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            user = serializer.save()
            user.set_password(user.password)
            user.save()
            return BaseResponse(data=serializer.data)
        return BaseResponse(message="注册失败", data=serializer.errors, code=ResultCode.CODE_PARAMETER_ERROR)

    @staticmethod
    def real_login(user_queryset, request):
        """
        用户登录
        :param user_queryset: queryset
        :param request: 请求
        :return: 登录结果
        """
        password = request.data.get('password')
        username = request.data.get('username')

        try:
            user = user_queryset.get(username=username)
        except User.DoesNotExist:
            return BaseResponse(message='登录失败, 用户名不存在', code=ResultCode.CODE_NO_MATCHING_ERROR)
        except Exception as e:
            return BaseResponse(message=f'{e}')

        if not user.check_password(password):
            return BaseResponse(message='密码错误', code=ResultCode.CODE_NO_MATCHING_ERROR)

        user_token = UserTokenSerializer(data={
            'token': tools.generate_token(),
            'user': user.id
        })
        result = {}
        old_token = UserToken.objects.filter(user=user)
        if old_token.count() == 0:
            result = tools.do_verified_saving(user_token, user)
        else:
            user_token.instance = old_token.first()
            if user_token.is_valid(raise_exception=True):
                result['data'] = user_token.to_representation(user_token.save())
        return BaseResponse(message='登录成功', data=result.get('data'))

    def do_login(self, request):
        """
        用户登录
        :param request: 请求
        :return: 登录结果
        """
        return UserApi.real_login(self.queryset, request)

    def query_user(self, request, action):
        """
        根据id查询用户
        :param request: 请求
        :param action: id
        :return: 用户对象
        """
        user = self.get_user(action)
        if user is None:
            return BaseResponse(message="用户不存在", code=ResultCode.CODE_NO_MATCHING_ERROR)
        user = self.serializer_class(instance=user)
        return BaseResponse(data=user.data)

    def update_user(self, request, action):
        user = self.get_user(action)
        if user is None:
            return BaseResponse(message="用户不存在", code=ResultCode.CODE_NO_MATCHING_ERROR)
        serializer = self.serializer_class(instance=user, data=request.data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return BaseResponse(data=serializer.data)
        return BaseResponse(message="用户修改失败", code=ResultCode.CODE_METHOD_ERROR)

    @staticmethod
    def change_password(request):
        old_password = request.data.get('oldPassword')
        new_password = request.data.get('newPassword')
        user = request.user
        if user.check_password(old_password):
            user.set_password(new_password)
            user.save()
            return BaseResponse(message='密码修改成功')
        else:
            return BaseResponse(message='原密码不正确', code=ResultCode.CODE_NO_MATCHING_ERROR)


class CourseTypeApi(TokenViewSet):
    """ 课程类型相关接口 """
    queryset = DbCourseType.objects.all()
    serializer_class = CourseTypeSerializer


class CourseApi(TokenViewSet):
    """ 课程相关接口，包括对课程的增删改查 """
    queryset = DbCourse.objects.all()
    serializer_class = CourseSerializer
    # authentication_classes = []
    search_fields = (
        SearchField('id', lookup='iexact'),
        SearchField('type', 'id', lookup='iexact'),
        SearchField('course_title'))
    ordering_fields = ['id']

    def get_course(self, id):
        course = None
        try:
            course = self.queryset.get(id=id)
        except DbCourse.DoesNotExist:
            pass
        return course

    @action(methods=['PUT'], detail=True)
    def add_visits(self, request, pk):
        course = self.get_course(pk)
        if course:
            course.visits += 1
            course.modified_time = tools.now()
            course.modified = request.user
            course.save()
            return BaseResponse(data=course.visits)
        return BaseResponse(message="失败", code=ResultCode.CODE_NO_MATCHING_ERROR)

    @action(methods=['PUT'], detail=True)
    def add_likes(self, request, pk):
        course = self.get_course(pk)
        if course:
            course.likes += 1
            course.modified_time = tools.now()
            course.modified = request.user
            course.save()
            return BaseResponse(data=course.likes)
        return BaseResponse(message="失败", code=ResultCode.CODE_NO_MATCHING_ERROR)


class CourseVideoApi(BaseViewSet):
    """ 课程视频相关接口 """
    queryset = DbCourseVideo.objects.all()
    serializer_class = CourseVideoSerializer

    search_fields = (
        SearchField('id', lookup='iexact'),
        SearchField('course', 'id', lookup='iexact'))


class StudyRecordApi(TokenViewSet):
    """ 学习记录相关接口 """
    queryset = DbStudyRecord.objects.all()
    serializer_class = StudyRecordSerializer
    search_fields = (SearchField('user_id', 'id', lookup='iexact'),)
